/**
 * \file
 *          teleMainBLThread.cpp
 * \brief
 *          Implements starter thread of entTelematicsMain
 *
 * \par Author (last changes):
 *          - Song Yang
 *          - Phone +65 65800179
 *          - Continental Automotive Singapore
 * \par Project Leader:
 *          - Mandy Sin
 *          - Phone +65 67799 819
 *          - Mandy.Sin@continental-corporation.com
 * \par Responsible Developer:
 *          - Song Yang
 *          - Phone +65 65800179
 *          - Continental Automotive Singapore
 * \par Responsible Architect:
 *          - Goh Hoe Chun
 *          - Phone +65 67799 586
 *          - Hoe.Chun.Goh@continental-corporation.com
 *
 * \par Project:
 *      DPCA2
 *
 * \par SW-Component:
 *      teleMainBLThread
 *
 * \par SW-Package:
 *      Telematics Main
 *
 * \par SW-Module:
 *      Telematics Main
 *
 * \par SW-Architecture Specification:
 *      DPCA_SW_AD_IMX
 *      003
 *
 * \par SW-Design Specification:
 *      DPCA_your_module_SW_DD
 *      your_doc_number
 *
 * \par SW-Test Case Specification:
 *      DPCA_your_module_SW_TS
 *      your_doc_number
 *
 * \par CM-Info:
 *      - teleMainBLThread.cpp-1:incl:DPCARSgp#1
 *      - uidc1282
 *
 * \note
 *      This is a note.
 *
 * \bug
 *      - there are no known bugs
 *
 * \par Module-History:
 *
 * \verbatim
 * Date                Author                 Reason
 * 20 Dec 2012         Song Yang           Initial Creation
 * The latest entry at the head of the history list.
 * \endverbatim
 *
 * \par Copyright Notice:
 * Copyright (C) 2011 Continental Automotive Singapore Pte Ltd.
 * Alle Rechte vorbehalten. All Rights Reserved.\n
 * The reproduction, transmission or use of this document or its contents is
 * not permitted without express written authority.\n
 * Offenders will be liable for damages. All rights, including rights created
 * by patent grant or registration of a utility model or design, are reserved.
 *
 * \ingroup GEN_TELE_MAIN
 */


#include "teleMainBLThread.h"
#include "teleMainBL.h"

#include "teleLogTrace.h"
#include "HiGraphQueue.h"
#include "HiGraphTimer.h"
#include "teleMainTimers.h"
#include "SystemConf.h"

#include "ConnMgrStateHigraph.h"
#include "RmtCfgStateHigraph.h"
#include "RmtCfgGetCfgStateHigraph.h"
#include "RmtCfgMonitorStateHigraph.h"
#include "tlmRmtCfgSrvApp.h"

#include "HtlmBcallEventHandler.h"
#include "HtlmEcallEventHandler.h"
#include "HiGraphTeleAudioBLEvent.h"

#include "UsbDiagBLHigraph.h"
#include "UsbDiagBLEvt.h"
#include "UsbDiagBLThread.h"

#include "tlmPushObjStateHigraph.h"
#include "tlmPushObjStateEvt.h"
#include "tlmUrlBackStateEvt.h"
#include "tlmUrlBackStateHigraph.h"

#include "entISysUMSGQ_def.h"


#include "ssw_IEmbRegistry.h"
#include "app_IEmbRegistryIDs.h"
#include "entISysConfiguration.h"

extern UsbDiagBLHigraph *pUsbDiagHigraph;
/*
 	Main HiGraph Queue for the components
*/
HiGraphQueue gTeleQueue(0, 300); /*DG CPP2ISQP-ISQPcpp Rule 8.4.6-SCC_GRANT_0010 */

/*
	Timer for teleMainBL components used in higraph
*/
HiGraphTimer gTeleTimer(teleBLMaxTimers,&gTeleQueue); /*DG CPP2ISQP-ISQPcpp Rule 8.4.6-SCC_GRANT_0010 */

/*
	Static class member attribute
*/

HiGraphBase** teleMainBLThread::mpStateMachines = 0; /*DG CPP2ISQP-ISQPcpp Rule 8.4.6-SCC_GRANT_0010 */


teleMainBLThread::teleMainBLThread(char* name,
									ThreadPriorityType priority,
									ThreadStackSizeType stackSize)
: RPCThread(name, priority, stackSize),
    mpHigraphAlarm(NIL),
    mpTeleQueueMutex(NIL),
    mStateMachinesSize(0),
    mpSignalHigraph(NIL),
    pObr(NIL)
{
    //#[ operation teleMainBLThread()
    //#]
}

teleMainBLThread::~teleMainBLThread(){

}
/*
teleMainBLThread * teleMainBLThread::getInstance()
{
	teleMainBLThread* teleMainInstance;

  	if(teleMainInstance == 0)
  	{
    	teleMainInstance = this;
     	LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE]:teleMainInstance::getInstance-create!\r\n");

  	}
  	return teleMainInstance;
}
*/
/**
 * \brief  Called by the Thread framework after preInstantiate
 *	Responsible to create all the instance resideds in this thread
 *
 * TestID:
 *
 * \param - none
 *
 * \return - none
 */
void teleMainBLThread::instantiate(void)
{
    //#[ operation instantiate()
	LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELEMAIN]:teleMainBLThread::instantiate\n");
    //#]
	this->pObr = new tele_obr();

	mStateMachinesSize  = gMAXTELE;											// Allocate the size  for number state machines
	mpStateMachines     = new HiGraphBase*[gMAXTELE];
	mpSignalHigraph     = new teleHigraphSignal(L"teleSignalHigraph",false);  // Create the Higraph Signal Event
	mpHigraphAlarm      = new teleHigraphAlarm(20,true,true);				// Create the alarm


    //mpStateMachines[gConnMgrState]         	= new ConnMgrStateHigraph();
	mpStateMachines[gEcallBLState]			= new HtlmEcallEventHandler();
	mpStateMachines[gRmtCfgSetState]         	= new RmtCfgStateHigraph();
    mpStateMachines[gRmtCfgGetState]         	= new RmtCfgGetCfgStateHigraph();
    mpStateMachines[gRmtCfgMonitorState]         	= new RmtCfgMonitorStateHigraph();
      mpStateMachines[gBcallBLState]			= new HtlmBcallEventHandler();
	mpStateMachines[gPushObjState]			= new tlmPushObjStateHigraph();
	mpStateMachines[gUrlBackBL]			= new tlmUrlBackStateHigraph();	


	if (1 == IsKitlEnable()) {
		mpStateMachines[gUsbDiagBL]  			= new UsbDiagBLHigraph();
		pUsbDiagHigraph = static_cast<UsbDiagBLHigraph *>(mpStateMachines[gUsbDiagBL]);
	} else {
		mpStateMachines[gUsbDiagBL]  			= NIL;
	}

    mpTeleQueueMutex                       	= new MutexLock();
}

/**
 * \brief  Called by the Thread framework when all the thread are instantiated.
 *	      instantiate and initialize class.
 *
 * TestID:
 *
 * \param - none
 *
 * \return - none
 */
void teleMainBLThread::initialize(void)
{
    //#[ operation initialize()
	LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELEMAIN]:teleMainBLThread::initialize\n");
	teleMainBL::getInstance().initialize();
    //#]

    // for UMSGQ, listening to entSystem_inst for USER state messages
	UMSGQ::getInstance().registerMSGEx(this->pObr,entSystem_inst,5,
	            entSysOom,
				entSysVf_Vehicle_Functions,
				entSysEng_IMX_SW_VERSION,
				entSysCfg,
				entSysComm_PROCESS_LIST);

	/*
		Register the mutex for Hi Graph queue
	*/
    gTeleQueue.setLocalMutex(mpTeleQueueMutex);

    /*
   	 Bind the signal to this thread
    */
    mpSignalHigraph->bind();

    /*
    	Register the signal with the queue object
    */
    gTeleQueue.setSignal(mpSignalHigraph);

    /*
    	Bind the alarm to this thread
    */
    mpHigraphAlarm->bind();
}

/**
 * \brief  Called by the Thread framework when all the thread are preInstantiated.
 *
 * TestID:
 *
 * \param - none
 *
 * \return - none
 */
 void teleMainBLThread::preInstantiate(void)
{
    //#[ operation preInstantiate()
	LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELEMAIN]:teleMainBLThread::preInstantiate\n");
    //#]
}



/**
* @brief This function used for processing the higraph event in the queue
*
* @return - none
*
* @note
*/
void teleMainBLThread::processEvent(void) /*DG CPP2ISQP-ISQPcpp Rule 8.7.1-SCC_GRANT_0006*/
{
    HiGraphEvent theEvent;
    uint16_t iterator = 0;

    while(gTeleQueue.getEvent(theEvent))
    {
        // Send this event to all the state machines for processing.
        for(iterator = 0; iterator < mStateMachinesSize; iterator++)
        {
            if(0 != mpStateMachines[iterator])
            {
                mpStateMachines[iterator]->processEvent(theEvent);
            }
        }
    }
}
/**
* @brief processAlarm: This function used for processing the higraph event in the queue periodically
*
* @param
* - none
*
* @return
* - none
*
* @note
*/
void teleMainBLThread::processAlarm(void)
{
    /* Make sure that the pending events are processed. */
    processEvent();

    /* Tick the timer */
    gTeleTimer.Tick();
}

/**
* @brief deInitialize: This function used for release all resources belongs to this thread.
*						This function should be called by telematics started thread when thread exit.
*
* @param
* - none
*
* @return
* - none
*
* @note
*/

void teleMainBLThread::deInitialize()       /*DG CPP2ISQP-ISQPcpp Rule 8.7.1-SCC_GRANT_0018*/
{
    delete mpTeleQueueMutex;
    delete mpHigraphAlarm;
    //delete mpStateMachines[gConnMgrState];
	delete mpStateMachines[gEcallBLState];
	delete mpStateMachines[gBcallBLState];
	delete mpStateMachines[gUsbDiagBL];
    delete mpStateMachines[gRmtCfgSetState];
    delete mpStateMachines[gRmtCfgGetState];
    delete mpStateMachines[gRmtCfgMonitorState];
	delete mpStateMachines[gPushObjState];
    delete[] mpStateMachines;
    delete mpSignalHigraph;
    delete pObr;
}


/**
* @brief This function is a contructor.
*
* @param[in] pName   : Name of the signal/event in string
* @param[in] bManual : Specifly whether the signal/event to be manual(TRUE) or auto reset(FALSE)
*
* @return
* - none
*
* @note
*/
teleHigraphSignal::teleHigraphSignal(LPCWSTR pName, bool bManual):ThreadSignal(pName,bManual)
{

}
/**
* @brief This function is a destructor.
*
* @param
* - none
*
* @return
* - none
*
* @note
*/
teleHigraphSignal::~teleHigraphSignal()
{
}

/**
* @brief This function is a callback function after the higraph signal is being signaled/triggered from os kernel
*
* @param[in] t   : the calling thread
*
* @return
* - none
*
* @note
*/
void teleHigraphSignal::hook(Thread *t)
{
   (static_cast<teleMainBLThread*>(t))->processEvent();
}


/**
* @brief This function is a contructor.
*
* @param[in] delay   : Delay of the starting alarm
* @param[in] autoset : Specifly whether to start the alarm auto (TRUE) or manually(FALSE)
* @param[in] repeat  : Specifly whether to perodically run (TRUE) or one time(FALSE)
*
* @return
* - none
*
* @note
*/
teleHigraphAlarm::teleHigraphAlarm(uint32_t delay,bool autoset,bool repeat):ThreadAlarm(delay, autoset, repeat)
{

}

/**
* @brief This function is a destructor.
*
* @param
* - none
*
* @return
* - none
*
* @note
*/
teleHigraphAlarm::~teleHigraphAlarm()
{

}

/**
* @brief This function is a callback function of the higraph alarm that is being signaled/triggered from os kernel after time out
*
* @param[in] t   : the calling thread
*
* @return
* - none
*
* @note
*/
void teleHigraphAlarm::hook(Thread *t)
{
   /** Call the function in the thread class to process this timer */
   (static_cast<teleMainBLThread *>(t))->processAlarm();
}

tele_obr::tele_obr(void)
{
}

tele_obr::~tele_obr(void)
{
	//#[ operation ~MyClass1()
	//#]
}

/**
* @brief This function is a callback function of the higraph alarm that is being signaled/triggered from os kernel after time out
*
* @param[in] t   : the calling thread
*
* \details
*	Covers: DPCA_USB_Video_SW_RD_120
*	Covers: DPCA_BT_Media_SW_RD_13
*
* @return
* - none
*
* @note
*/
void tele_obr::__hndUpdateByValue(ObsObd * theCallingObserved, obsObdStatus status, const uint8_t* dataPackage, const uint16_t size )
{
	// How to decode UMSGQ
    // status = [8bits SubmitterId][8bits EventId]
    uc8_t msgSubmitterID = static_cast<uc8_t>((status & 0x0000FF00) >> 8);
    uc8_t msgEventID     = static_cast<uc8_t>(status & 0x000000FF);
    uint32_t mProcessList;

    switch (msgSubmitterID)
    {
        case entSystem_inst:
        {
            switch(msgEventID)
            {
            case entSysVf_Vehicle_Functions:
                         {
                                if(dataPackage[0] == VFUMSG_NEW_VIN_DETECTED)
                                {
                                    tlmRmtCfgSrvApp::GetInstance()->UpdateGenericVin(dataPackage);
                                    teleMainBL::getInstance().Admin_DetectVINConflict(VIN_GENERAL);
                                }
                                break;
                          }
            case entSysEng_IMX_SW_VERSION:
                    {
                        tlmRmtCfgSrvApp::GetInstance()->UpdateImxSysInfo(dataPackage);
                        break;
                        }
            case entSysCfg:
                    {
                        LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TLM_MSGSRV]:<%s> %d\n", __FUNCTION__, dataPackage[0]);
                        if(entSysCfg_CURRENT_LANG == dataPackage[0])
                        {
                            tlmRmtCfgSrvApp::GetInstance()->UpdateLanguage(dataPackage[1]);
                        }
                        
                        break;
                        }
		    case entSysComm_PROCESS_LIST:
                {
                    LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE]:%s - entSysComm_PROCESS_LIST received",__FUNCTION__);
                    memcpy(&mProcessList,dataPackage,sizeof(uint32_t));
                    if((entNavMask & mProcessList) == entNavMask){
                        LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE]:%s - EVT_PUSH_OBJECT_NAVI_READY posted",__FUNCTION__);
                        gTeleQueue.postEvent(EVT_PUSH_OBJECT_NAVI_READY, NIL);
                    }
                    

                    //L.YANG. Should use below when WEB module code is integrated.
                    //if((entWebMask & mProcessList) == entWebMask){
                    if(1){
                        LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE]:%s - EVT_URL_BACK_WEB_READY posted",__FUNCTION__);
                        gTeleQueue.postEvent(EVT_URL_BACK_WEB_READY, NIL);
                    }
                    break;
                }

            	case entSysOom:
				{
					switch(dataPackage[0])
					{
		                case entSysOom_USER_SET_LOCKED:
		                {
                            if (entSysOom_USER_SET_LOCKED != mUserState)
                            {
                                LOG_PRINT(DPCA_TELE_MAIN_INFO,"[teleaudio]:entSysOom_USER_SET_LOCKED is received");
                               // gTeleQueue.postEvent(LifeCycle_USER_SETLOCKED, 1);
                                mUserState = entSysOom_USER_SET_LOCKED;
                            }
		                    break;
		                }
		                case entSysOom_USER_SET_OFF:
		                {
                            if (entSysOom_USER_SET_OFF != mUserState)
                            {
                                LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE][Thread][BL]:entSysOom_USER_SET_OFF is received");
                               // gTeleQueue.postEvent(LifeCycle_USER_SETOFF, 1);
								gTeleQueue.postEvent(EVT_USBDIAG_VOOR, 1);
                                mUserState = entSysOom_USER_SET_OFF;
                            }
		                    break;
		                }
		                case entSysOom_USER_SET_ON:
		                {
                            if (entSysOom_USER_SET_ON != mUserState)
                            {
                                LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE][Thread][BL]:entSysOom_USER_SET_ON is received");
                               // gTeleQueue.postEvent(LifeCycle_USER_SETON, 1);
								gTeleQueue.postEvent(EVT_USBDIAG_GOTOSLEEP, 1);
                                mUserState = entSysOom_USER_SET_ON;
                            }
		                    break;
		                }
		                case entSysOom_USER_SET_USER_ON:
		                {
                            if (entSysOom_USER_SET_USER_ON != mUserState)
                            {
                                LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELE][Thread][BL]:entSysOom_USER_SET_USER_ON is received");
                                
				gTeleQueue.postEvent(EVT_USBDIAG_NORMAL, 1);
                                mUserState = entSysOom_USER_SET_USER_ON;
                            }
                            
                                    teleMainBL::getInstance().Admin_DetectVINConflict(VIN_SET_USER_ON);
		                    break;
		                }
		                default:
		                {
							// entSysOom msgEventID NOT HANDLED
							LOG_PRINT(DPCA_TELE_MAIN_WARN,"[TELE][Thread][BL]:Unhandled entSysOom msgEventID!");
		                    break;
		                }
					}
					break;
            	}
				default:
		        {
					// entSystem_inst msgEventID NOT HANDLED
					LOG_PRINT(DPCA_TELE_MAIN_WARN,"[AV][Thread][BL]:Unhandled entSystem_inst msgEventID!");
		            break;
		        }
            }
			break;
        }

        default:
        {
			// msgSubmitterID NOT HANDLED
			LOG_PRINT(DPCA_TELE_MAIN_WARN,"[AV][Thread][BL]:Unhandled msgSubmitterID!");
            break;
        }
    }

    return;
}

uint8_t teleMainBLThread::IsKitlEnable(void)
{
	DWORD retVal = 0;
	uint8_t  x = 0;
	uint32_t actualOut = 0;
	retVal = ssw_ergUserReadData(ERG_USER_SYSTEM, ERG_DPCA2_CONF_NAVI_MAPSCROLL, &x, sizeof(uint8_t), &actualOut);
	if(ER_ERG_SUCCESS == retVal)
	{
		LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELEMAIN]:teleMainBLThread::ERG_DPCA2_CONF_NAVI_MAPSCROLL %d\n",x);
	}
	else
	{
	    LOG_PRINT(DPCA_TELE_MAIN_INFO,"[TELEMAIN]:teleMainBLThread::ERG_DPCA2_CONF_NAVI_MAPSCROLL FAIL!\n");
	}
	return x;
}
